package pishen;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.cli.PosixParser;

import edu.uci.ics.jung.graph.Graph;
import edu.uci.ics.jung.graph.SparseGraph;
import edu.uci.ics.jung.graph.util.EdgeType;

public class PartAHandler {
	private String inputGraph, inputSource, inputBlockList, diffusionModel;
	private Graph<Node, Edge> graph;
	private HashMap<String, Node> nodeMap;
	private ArrayList<Node> sourceList;
	
	public void startSimulate(String[] args){
		parseCommandLine(args);
		
		String graphName = (new File(inputGraph)).getName();
		
		File partADir = new File("part_a");
		File partBDir = new File("part_b");
		if(!partADir.exists()){
			partADir.mkdir();
		}
		if(!partBDir.exists()){
			partBDir.mkdir();
		}
		
		initGraph(inputGraph, inputSource, inputBlockList);
		
		System.out.println("graph size=" + graph.getVertexCount());
		
		if(diffusionModel.equals("IC") || diffusionModel.equals("all")){
			System.out.println("start IC");
			ICSimulator ic = new ICSimulator(duplicateGraph(), (List<Node>)(sourceList.clone()));
			ic.startSimulate();
			writeInfectedNodes("part_a/ic_" + graphName, ic.getInfectedList());
			
			if(inputBlockList == null){
				BlockModelA bma = new BlockModelA(duplicateGraph(), (List<Node>)(sourceList.clone()), "IC");
				bma.run();
				for(int level = 0; level < 6; level++){
					writeBlockList("part_b/ic_0.0" + level + "_" + graphName, bma.getBlockedLists()[level]);
				}
			}
		}
		if(diffusionModel.equals("LT") || diffusionModel.equals("all")){
			System.out.println("start LT");
			LTSimulator lt = new LTSimulator(duplicateGraph(), (List<Node>)(sourceList.clone()));
			lt.startSimulate();
			writeInfectedNodes("part_a/lt_" + graphName, lt.getInfectedList());
			
			if(inputBlockList == null){
				BlockModelA bma = new BlockModelA(duplicateGraph(), (List<Node>)(sourceList.clone()), "LT");
				bma.run();
				for(int level = 0; level < 6; level++){
					writeBlockList("part_b/lt_0.0" + level + "_" + graphName, bma.getBlockedLists()[level]);
				}
			}
		}
		if(diffusionModel.equals("Third") || diffusionModel.equals("all")){
			System.out.println("start Third");
			ThirdDiffusionSimulator third = new ThirdDiffusionSimulator(graph, (List<Node>)(sourceList.clone()));
			third.startSimulate();
			writeInfectedNodes("part_a/third_" + graphName, third.getInfectedList());
			
			if(inputBlockList == null){
				BlockModelA bma = new BlockModelA(duplicateGraph(), (List<Node>)(sourceList.clone()), "Third");
				bma.run();
				for(int level = 0; level < 6; level++){
					writeBlockList("part_b/third_0.0" + level + "_" + graphName, bma.getBlockedLists()[level]);
				}
			}
		}
		
	}
	
	public void parseCommandLine(String[] args){
		Options options = new Options();
		CommandLineParser parser = new PosixParser();
		CommandLine cmd = null;
		options.addOption("g", true, "input graph");
		options.addOption("s", true, "source nodes");
		options.addOption("b", true, "block nodes");
		options.addOption("m", true, "diffusion model");
		try {
			cmd = parser.parse(options, args);
		} catch (ParseException e) {
			e.printStackTrace();
		}
		if(cmd.hasOption("g")){
			inputGraph = cmd.getOptionValue("g");
		}
		if(cmd.hasOption("s")){
			inputSource = cmd.getOptionValue("s");
		}
		if(cmd.hasOption("b")){
			inputBlockList = cmd.getOptionValue("b");
		}
		if(cmd.hasOption("m")){
			diffusionModel = cmd.getOptionValue("m");
		}
	}
	
	private void writeInfectedNodes(String fileName, List<Node> infectedList){
		try {
			BufferedWriter out = new BufferedWriter(new FileWriter(fileName));
			for(Node node: infectedList){
				out.write(node.toString());
				out.newLine();
			}
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void writeBlockList(String fileName, List<Node> blockList){
		try {
			BufferedWriter out = new BufferedWriter(new FileWriter(fileName));
			for(Node node: blockList){
				out.write(node.toString());
				out.newLine();
			}
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private Graph<Node, Edge> duplicateGraph(){
		Graph<Node, Edge> duplicatedGraph = new SparseGraph<Node, Edge>();
		for(Node node: graph.getVertices()){
			duplicatedGraph.addVertex(node);
		}
		for(Edge edge: graph.getEdges()){
			duplicatedGraph.addEdge(edge, graph.getSource(edge), graph.getDest(edge), EdgeType.DIRECTED);
		}
		return duplicatedGraph;
	}
	
	private void initGraph(String graphPath, String sourcePath, String inputBlockList){
		graph = new SparseGraph<Node, Edge>(); //input is Directed Graph
		nodeMap = new HashMap<String, Node>();
		sourceList = new ArrayList<Node>();
		try {
			//parse graph
			BufferedReader in = new BufferedReader(new FileReader(graphPath));
			String line = null;
			while((line = in.readLine()) != null){
				String nodeStr[] = line.split("\t");
				graph.addEdge(new Edge(), new Node(nodeStr[0]), new Node(nodeStr[1]), EdgeType.DIRECTED);
			}
			in.close();
			//initial the map
			for(Node node: graph.getVertices()){
				nodeMap.put(node.getId(), node);
			}
			//remove block nodes
			if(inputBlockList != null){
				in = new BufferedReader(new FileReader(inputBlockList));
				while((line = in.readLine()) != null){
					graph.removeVertex(nodeMap.get(line));
					nodeMap.remove(line);
				}
				in.close();
			}
			//parse source
			in = new BufferedReader(new FileReader(sourcePath));
			while((line = in.readLine()) != null){
				Node sourceNode = nodeMap.get(line);
				if(sourceNode != null){
					sourceList.add(sourceNode);
				}
			}
			in.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}
